#include "ahuproc.h"
#include "ahumqtt.h"
#include "ahufsm.h"
#include "ahupidfunc.h"
#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

extern ahu_dev_t *ahu_dev_hd;
extern struct mosquitto *mqtt_ahu;
extern ahu_fsmsets_t ahu_fsmset[];

/* 调试使用，打印所有的点位 */
void printf_debug()
{
#if 1
    ahu_dev_t *ahu_pos;
        printf("---- \n");
    list_for_each_entry(ahu_pos, &ahu_dev_hd->list, list){

        int i;
        for(i=0; i<ahu_pos->vir_num; i++){
            if((ahu_pos->vp+i)->tag == TypeOfVal_DOUBLE){

                printf("%s %s %s %lf \n", (ahu_pos->vp+i)->name, (ahu_pos->vp+i)->dev_key, \
                                        (ahu_pos->vp+i)->func, (ahu_pos->vp+i)->val.d);
            }
            if((ahu_pos->vp+i)->tag == TypeOfVal_INT){
                printf("%s %s %s %d \n", (ahu_pos->vp+i)->name, (ahu_pos->vp+i)->dev_key, \
                                        (ahu_pos->vp+i)->func, (ahu_pos->vp+i)->val.i);
            }
            if((ahu_pos->vp+i)->tag == TypeOfVal_BOOL){
                printf("%s %s %s %d \n", (ahu_pos->vp+i)->name, (ahu_pos->vp+i)->dev_key, \
                                        (ahu_pos->vp+i)->func, (ahu_pos->vp+i)->val.b);
            }
        }
        for(i=0; i<ahu_pos->real_num; i++){

            if((ahu_pos->rp+i)->tag == TypeOfVal_BOOL){
                printf("%s %s %s %d \n", (ahu_pos->rp+i)->name, (ahu_pos->rp+i)->dev_key, \
                                        (ahu_pos->rp+i)->func, (ahu_pos->rp+i)->val.b);
            }
            if((ahu_pos->rp+i)->tag == TypeOfVal_DOUBLE){
                printf("%s %s %s %lf \n", (ahu_pos->rp+i)->name, (ahu_pos->rp+i)->dev_key, \
                                        (ahu_pos->rp+i)->func, (ahu_pos->rp+i)->val.d);
            }
            if((ahu_pos->rp+i)->tag == TypeOfVal_INT){
                printf("%s %s %s %d \n", (ahu_pos->rp+i)->name, (ahu_pos->rp+i)->dev_key, \
                                        (ahu_pos->rp+i)->func, (ahu_pos->rp+i)->val.i);
            }
        }

    }
#endif
}

/* 向@json报文中添加错误码
 * @ec: 错误码
 */
void add_errcode2json(struct json_object *jroot, enum error_code ec)
{
    struct json_object *jec;

    jec = json_object_new_int(ec);
    json_object_object_add(jroot, "errorCode", jec);
}

/* 给初始化设备虚点位属性
 *   name       jval
 *    |         |
 * "RM-TSP":8.0
 * @point：被初始化的设备
 * @name：json中提取的点位name
 * @jval：json中提取的点位value
 */
static void extract_vp_2pointprop(point_prop_t *point, char *name, struct json_object *jval)
{
    strcpy(point->name, name);
    strcpy(point->func, name);

    switch(point->tag){
        case TypeOfVal_BOOL:    point->val.b = json_object_get_boolean(jval);   break;
        case TypeOfVal_INT:     point->val.i = json_object_get_int(jval);       break;
        case TypeOfVal_DOUBLE:  point->val.d = json_object_get_double(jval);    break;
        default: break;
    }
}

/* 提取空调虚点
 * @jfunc： json报文中的function字段
 * @ahu_newdev： 空调设备，解析@jfunc中的虚点信息，保存到此位置
*/
static void extract_ahu_vp(struct json_object *jfunc, ahu_dev_t *ahu_newdev)
{
    int i, size;
    char topic[128];
    enum type_of_val tp_val;

    json_object_object_foreach(jfunc, key, jval){

        switch(json_object_get_type(jval)){
            case json_type_null:    continue;  // 跳过null对象
            case json_type_int:     tp_val = TypeOfVal_INT;     break;
            case json_type_double:  tp_val = TypeOfVal_DOUBLE;  break;
            case json_type_boolean: tp_val = TypeOfVal_BOOL;    break;
            case json_type_string:  tp_val = TypeOfVal_STRING;  break;
            default:    break;
        }

        /* 总虚点个数 */
        ahu_newdev->vir_num += 1;
        size = sizeof(point_prop_t) * ahu_newdev->vir_num;

        /* 扩增虚点 */
        ahu_newdev->vp = realloc(ahu_newdev->vp, size);
        if(ahu_newdev->vp == NULL){
            ES_PRT_ERROR("AHU: null memory when extend vp \n");
        }
        i = ahu_newdev->vir_num - 1;
        (ahu_newdev->vp+i)->tag = tp_val;

        /* 保存虚点的deviceKey到设备描述符 */
        strcpy((ahu_newdev->vp+i)->dev_key, ahu_newdev->device_id);
        /* 保存虚点的function，value到设备描述符 */
        extract_vp_2pointprop(ahu_newdev->vp+i, key, jval);

        /* 每解析一个虚点就订阅一个虚点 */
        sprintf(topic, "%s/%s/command", MQTT_LOCAL_PREFIX, (ahu_newdev->vp+i)->dev_key);
        mosquitto_subscribe(mqtt_ahu, NULL, topic, 0);
    }

}

/* 提取空调虚点
 * @point： 设备的点位描述符指针
 * @dk： 从json中提取的deviceKey
 * @func： 从json中提取的function
*/
static void extract_rp_2pointprop(point_prop_t *point, char *name, const char *dk, const char *func)
{
    strcpy(point->name, name);
    strcpy(point->dev_key, dk);
    strcpy(point->func, func);

    /* 每解析一个点就订阅一个点 */
    char topic[128];
    sprintf(topic, "%s/%s", MQTT_LOCAL_PREFIX, dk);
    mosquitto_subscribe(mqtt_ahu, NULL, topic, 0);
}

/* 提取空调实点
 * @jcfg： json报文中的configuration字段
 * @ahu_newdev： 空调设备，解析@jcfg中的虚点信息，保存到此位置
*/
static void extract_ahu_rp(struct json_object *jcfg, ahu_dev_t *ahu_newdev)
{
    struct json_object *jdk;
    struct json_object *jmap;
    struct json_object *jchan;

    int i;

    /* 遍历json报文中的configuration字段的每条信息 */
    json_object_object_foreach(jcfg, key, jval){
        if(strcmp(key, "virDevType") == 0){
            continue;
        }
    
        /* 提取deviceKey */
        if( !json_object_object_get_ex(jval, "deviceKey", &jdk) ){
            return;
        }
        /* 跳过 "deviceKey":"" 或 "deviceKey":null  */
        if(json_object_get_type(jdk) == json_type_null || strcmp(json_object_get_string(jdk), "") == 0){
            continue;
        }

        if( !json_object_object_get_ex(jval, "jsonMap", &jmap) ){
            return;
        }

        if( !json_object_object_get_ex(jmap, "key", &jchan) ){
            return;
        }
        /* deviceKey 和 function 不能位空 */
        if(json_object_get_type(jchan) == json_type_null || strcmp(json_object_get_string(jchan), "") == 0){
            continue;
        }

        /* 统计实点总个数 */
        ahu_newdev->real_num++;
        /* 扩增实点 */
        ahu_newdev->rp = realloc(ahu_newdev->rp, sizeof(point_prop_t) * ahu_newdev->real_num);
        i = ahu_newdev->real_num - 1;
        /* 将实点的devicekey和function配置到设备描述符中 */
        extract_rp_2pointprop(ahu_newdev->rp+i, key, json_object_get_string(jdk), json_object_get_string(jchan));
    }
}

/* 从json报文中添加设备 
 * @ahu_newdev：设备描述符
 * @jdata：json报文中的data字段
 */
static int  _add_ahu_dev_from_json(struct json_object *jdata, ahu_dev_t *ahu_newdev)
{
    struct json_object *jfunc, *jcfg;

    /* get data/function object, return if unexist */
    if( !json_object_object_get_ex(jdata, "function", &jfunc) ){
        return ErrNoJsonObj;
    }

    /* get data/configuration object, return if unexist */
    if( !json_object_object_get_ex(jdata, "configuration", &jcfg) ){
        return ErrNoJsonObj;
    }

    /* 提取虚点信息到设备描述符 */
    extract_ahu_vp(jfunc, ahu_newdev);
    /* 提取实点信息到设备描述符 */
    extract_ahu_rp(jcfg, ahu_newdev);
    /* 实点+虚点总个数 */
    ahu_newdev->points_num = ahu_newdev->vir_num + ahu_newdev->real_num;

    return Success;
}

/* 解析json, 并添新设备 */
static int add_ahu_dev_from_json(struct json_object *jroot)
{
    struct json_object *jdata, *jcfg, *jvir_dev_tp;

    if(!json_object_object_get_ex(jroot, "data", &jdata)){
        return ErrNoJsonObj;
    }
    if(!json_object_object_get_ex(jdata, "configuration", &jcfg)){
        return ErrNoJsonObj;
    }
    if(!json_object_object_get_ex(jcfg, "virDevType", &jvir_dev_tp)){
        return ErrNoJsonObj;
    }
    /* 只添加AHU设备 */
    if(strcmp(APPNAME, json_object_get_string(jvir_dev_tp)) != 0){
        return ErrNoDev;
    }
    //printf("%s \n", json_object_to_json_string_ext(jroot, JSON_C_TO_STRING_PRETTY));

    struct json_object *jdk;

    /* 获取虚点的deviceKey，并作为当前设备实例的deviceID */
    jdk = json_object_object_get(jdata, "deviceKey");

    ahu_dev_t *ahu_pos;
    
     /* 遍历已有的设备，判重 */
    list_for_each_entry(ahu_pos, &ahu_dev_hd->list, list){

        if(strcmp(ahu_pos->device_id, json_object_get_string(jdk)) == 0){
            ES_PRT_ERROR("AHU: repeat device key when add new device, old_deviceKey[%s], new_deviceKey[%s] \n", \
                            ahu_pos->device_id, json_object_get_string(jdk));
            return ErrExist;
        }
    }

    /* 申请一个新空调设备 */
    ahu_dev_t *ahu_newdev = calloc(1, sizeof(ahu_dev_t)*1);
    /* 初始化 */
    ahu_newdev->add_dev = false;
    ahu_newdev->vp = NULL;
    ahu_newdev->rp = NULL;
    ahu_newdev->vir_num = 0;
    ahu_newdev->real_num = 0;
    ahu_newdev->fsm.cur_state = S_INIT;
    ahu_newdev->fsm.fsmset = ahu_fsmset;    // 状态机的入口

    pthread_mutex_init(&ahu_newdev->lock, NULL);

    /* 将虚点deviceKey作为整个设备的id */
    strcpy(ahu_newdev->device_id, json_object_get_string(jdk));
    ES_PRT_DEBUG("AHU: new deivceID = %s \n", ahu_newdev->device_id);
    /* 配置设备描述符 */
    _add_ahu_dev_from_json(jdata, ahu_newdev);
    ahu_newdev->add_dev = true;

    list_add_tail(&ahu_newdev->list, &ahu_dev_hd->list);

    //TODO: 其他pid初始化
    /* 温度pid初始化 */
    pidinit_hmdt(ahu_newdev);
    /* 湿度pid初始化 */
    pidinit_temp(ahu_newdev);

    return Success;
}

/* 保存设备到本地 */
static void add_ahu_dev_2local(struct json_object *jroot)
{
    struct json_object *jdata;

    /* get data object */
    if(!json_object_object_get_ex(jroot, "data", &jdata)){
        return;
    }

    /* 获取虚点的deviceKey */
    struct json_object *jdk;
    jdk = json_object_object_get(jdata, "deviceKey");

    const char *dk;
    dk = json_object_get_string(jdk);
    /* 用deviceKey组合成文件  AppName_deviceKey.json */
    char file_name[100];
    sprintf(file_name, "%s_%s.json", APPNAME, dk);

    /* 组合：文件所在目录/文件名 */
    char full_path[150];
    sprintf(full_path, "%s/%s", LOCAL_CONF_DIR, file_name);

    DIR *dirp;
    struct dirent *ent;

    /* 如果目录不存在就创建目录 */
    if(access(LOCAL_CONF_DIR, F_OK) != 0){
        mkdir(LOCAL_CONF_DIR, 0777);
    }

    /* 如果目录存在就创建创建文件 */
    if(access(LOCAL_CONF_DIR, F_OK) == 0){

        ES_PRT_INFO("Saving new device to local: %s \n", LOCAL_CONF_DIR);

        dirp = opendir(LOCAL_CONF_DIR);

        /* 如果文件存在就删除文件，再创建 */
        while( (ent = readdir(dirp)) != NULL ){
            if ( (strcmp(".", ent->d_name) == 0 ) || (strcmp("..", ent->d_name) == 0) ){
                continue;
            }
            if(strcmp(ent->d_name, file_name) == 0){
                ES_PRT_ERROR("File: %s has existed, when save points to local. will remove it, and then create new json \n", file_name);
                unlink(file_name);
            }
        }

        /* 创建文件 */
        ES_PRT_INFO("Creating new local file: %s, writing json to it. \n", full_path);
        json_object_to_file_ext(full_path, jroot, JSON_C_TO_STRING_PRETTY);

        closedir(dirp);
    }

}

static void add_dev_from_file(char *filename)
{
    struct json_object *jroot;

    char fullname[150];
    sprintf(fullname, "%s/%s", LOCAL_CONF_DIR, filename);
    printf("%s \n", fullname);

    jroot = json_object_from_file(fullname);

    ahu_mqtt_cmd_adddevice(jroot);
}

/* 读取本地配置目录，添加设备 */
void add_dev_from_local()
{
    /* 如果目录不存在就创建目录 */
    if(access(LOCAL_CONF_DIR, F_OK) != 0){
        mkdir(LOCAL_CONF_DIR, 0777);
    }

    DIR *dirp;
    struct dirent *ent;

    /* 如果目录存在就创建遍历所有文件，读取文件，添加设备到设备描述符 */
    if(access(LOCAL_CONF_DIR, F_OK) == 0){

        dirp = opendir(LOCAL_CONF_DIR);

        while( (ent = readdir(dirp)) != NULL ){
            if ( (strcmp(".", ent->d_name) == 0 ) || (strcmp("..", ent->d_name) == 0) ){
                continue;
            }

            add_dev_from_file(ent->d_name);
        }

        closedir(dirp);
    }
}

/* 添加设备 */
enum error_code ahu_mqtt_cmd_adddevice(struct json_object *jroot)
{
    struct json_object *jchan;
    enum error_code err;

    /* 提取 channel 字段, 不是 "channel":"virDev" 的报文不处理 */
    if( json_object_object_get_ex(jroot, "channel", &jchan) ){
        if(strcmp(json_object_get_string(jchan), "virDev") != 0){
            ES_PRT_INFO("AHU: \"channel\" !=  virDev when addDevice. return. \n");
            return ErrFalse;
        }
    }else{
        ES_PRT_INFO("AHU: No \"channel\" when addDevice. return. \n");
        return ErrFalse;
    }

    /* 添加设备 */
    err = add_ahu_dev_from_json(jroot);

    /* 加上errcode */
    add_errcode2json(jroot, err);

    const char *msg_ext;
    msg_ext = json_object_to_json_string_ext(jroot, JSON_C_TO_STRING_PRETTY);

    /* 发送给bacnet */
    ES_PRT_INFO("AHU: Send new device to /local/app/bacnet/command ... \n");
    mosquitto_publish(mqtt_ahu, NULL, "/local/app/bacnet/command", strlen(msg_ext), msg_ext, 0, 0);

    if(err == Success){
        return Success;
    }

    return ErrFalse;
}

/* 收到更新点位的报文，根据deviceKey和function将其配置到设别描述符中
 * @dk: 从json中提取的deviceKey
 * @chan：从json中提取的function
 * @jval：json各式的value
 */
static enum error_code update_points_2dev(const char *dk, char *chan, struct json_object *jval)
{
    int i;

    ahu_dev_t *ahu_pos;
    /* 遍历所有设备，根据deviceKey和function找到点位 */
    list_for_each_entry(ahu_pos, &ahu_dev_hd->list, list){
        /* 遍历当前设备的所有虚点 */
        for(i=0; i<ahu_pos->vir_num; i++){
            /* deviceKey 和 function 是否匹配 */
            if(strcmp((ahu_pos->vp+i)->dev_key, dk) == 0 && strcmp((ahu_pos->vp+i)->func, chan) == 0){

                /* 根据类型赋值到设备描述符 */
                switch(json_object_get_type(jval)){
                    case json_type_null:    continue;  // 跳过null对象
                    case json_type_int:
                        (ahu_pos->vp+i)->tag = TypeOfVal_INT;
                        (ahu_pos->vp+i)->val.i = json_object_get_int(jval);
                        break;
                    case json_type_double:
                        (ahu_pos->vp+i)->tag = TypeOfVal_DOUBLE;
                        (ahu_pos->vp+i)->val.d = json_object_get_double(jval);
                        break;
                    case json_type_boolean:
                        (ahu_pos->vp+i)->tag = TypeOfVal_BOOL;
                        (ahu_pos->vp+i)->val.b = json_object_get_boolean(jval);
                        break;
                    default:    break;
                }

                return Success;
            }

        }
        /* 遍历当前设备的所有实点 */
        for(i=0; i<ahu_pos->real_num; i++){

            if(strcmp((ahu_pos->rp+i)->dev_key, dk) == 0 && strcmp((ahu_pos->rp+i)->func, chan) == 0){
                switch(json_object_get_type(jval)){
                    case json_type_null:    continue;  // 跳过null对象
                    case json_type_int:
                        (ahu_pos->rp+i)->tag = TypeOfVal_INT;
                        (ahu_pos->rp+i)->val.i = json_object_get_int(jval);
                        break;
                    case json_type_double:
                        (ahu_pos->rp+i)->tag = TypeOfVal_DOUBLE;
                        (ahu_pos->rp+i)->val.d = json_object_get_double(jval);
                        break;
                    case json_type_boolean:
                        (ahu_pos->rp+i)->tag = TypeOfVal_BOOL;
                        (ahu_pos->rp+i)->val.b = json_object_get_boolean(jval);
                        break;
                    default:    break;
                }

                return Success;
            }

        }
    }

    return ErrFalse;
}

/* 处理json报文：cmd=write的报文 */
static enum error_code ahu_mqtt_cmd_write(struct json_object *jroot)
{
    /* 如果还没有addDevice，链表为空，就不做处理 */
    if(list_empty(&ahu_dev_hd->list) == 1){
        return ErrFalse;
    }

    struct json_object *jdk, *jfunc;
    /* 提取json中deviceKey字段 */
    if( json_object_object_get_ex(jroot, "deviceKey", &jdk) == false ){
        return ErrFalse;
    }
    /* 提取json中function字段 */
    if( json_object_object_get_ex(jroot, "function", &jfunc) == false ){
        return ErrFalse;
    }

    /* 遍历function中的每个条目 */
    json_object_object_foreach(jfunc, key, jval){
        /* 解析每个点位，配置到设备描述符中 */
        update_points_2dev(json_object_get_string(jdk), key, jval);
    }

    /* 默认success, TODO: 根据update_points_2dev返回值传参 */
    add_errcode2json(jroot, Success);

    /* del cmd 对象 */
    const char *msg_ext;
    json_object_object_del(jroot, "cmd");
    msg_ext = json_object_to_json_string_ext(jroot, JSON_C_TO_STRING_PRETTY);

    /* 发送出去 */
    char topic[128];
    /* topic = /local/gatewaydeviceKey/<deviceKey> */
    sprintf(topic, "%s/%s", MQTT_LOCAL_PREFIX, json_object_get_string(jdk));
    mosquitto_publish(mqtt_ahu, NULL, topic, strlen(msg_ext), msg_ext, 0, 0);

    return Success;
}

static void update_points_2file(char *filename, struct json_object *jnew)
{
    char fullname[150];
    sprintf(fullname, "%s/%s", LOCAL_CONF_DIR, filename);

    json_object *jroot = json_object_from_file(fullname);
    json_object *jdata = json_object_object_get(jroot, "data");
    json_object *jfunc = json_object_object_get(jdata, "function");

    json_object *jnew_Func = json_object_object_get(jnew, "function");

    json_object_object_foreach(jnew_Func, new_key, jnew_val){
        /* 根据NewKey删掉文件中对应的object，然后把新的Key-Value写回文件 */
printf("new_key = %s \n", new_key);
        json_object_object_del(jfunc, new_key);
        json_object_object_add(jfunc, new_key, jnew_val);
    }

    json_object_to_file_ext(fullname, jroot, JSON_C_TO_STRING_PRETTY);
}

static void update_points_2local(struct json_object *jroot)
{
    struct json_object *jdk;
    /* 提取json中deviceKey字段 */
    if( json_object_object_get_ex(jroot, "deviceKey", &jdk) == false ){
        return;
    }

    const char *dk;
    dk = json_object_get_string(jdk);

    DIR *dirp;
    struct dirent *ent;

    dirp = opendir(LOCAL_CONF_DIR);

    while( (ent = readdir(dirp)) != NULL ){
        if ( (strcmp(".", ent->d_name) == 0 ) || (strcmp("..", ent->d_name) == 0) ){
                continue;
        }
        /* 找到虚点所在的文件 */
        if(strstr(ent->d_name, dk) != NULL){
            update_points_2file(ent->d_name, jroot);
        }
    }

    closedir(dirp);
}

/* 从本地删除设备文件 */
static void del_dev_from_local(struct json_object *jroot)
{
    struct json_object *jdata, *jdk;

    if(!json_object_object_get_ex(jroot, "data", &jdata)){
        return;
    }

    if(!json_object_object_get_ex(jdata, "deviceKey", &jdk)){
        return;
    }

    const char *dk;
    dk = json_object_get_string(jdk);

    DIR *dirp;
    struct dirent *ent;

    dirp = opendir(LOCAL_CONF_DIR);

    char fullname[400];

    while( (ent = readdir(dirp)) != NULL ){
        if ( (strcmp(".", ent->d_name) == 0 ) || (strcmp("..", ent->d_name) == 0) ){
                continue;
        }

        /* 找到虚点所在的文件 */
        if(strstr(ent->d_name, dk) != NULL){
            sprintf(fullname, "%s/%s", LOCAL_CONF_DIR, ent->d_name);
            unlink(fullname);
            ES_PRT_INFO("AHU: Delete device from local (%s) \n", fullname);
        }
    }

    closedir(dirp);
}

/* 从设备描述符删除设备 */
static void del_dev_from_dp(struct json_object *jroot)
{
    struct json_object *jdata, *jvir_dev_type, *jdk;

    if(!json_object_object_get_ex(jroot, "data", &jdata)){
        return;
    }
    if(!json_object_object_get_ex(jdata, "virDevType", &jvir_dev_type)){
        return;
    }

    /* 不是AHU,不处理 */
    if(strcmp("AHU", json_object_get_string(jvir_dev_type)) != 0){
        return;
    }

    if(!json_object_object_get_ex(jdata, "deviceKey", &jdk)){
        return;
    }

    const char *dk;
    dk = json_object_get_string(jdk);

    ahu_dev_t *pos, *n;
    list_for_each_entry_safe(pos, n, &ahu_dev_hd->list, list){
        if(strcmp(pos->device_id, dk) == 0){
            free(pos->vp);
            free(pos->rp);
            pthread_mutex_destroy(&pos->lock);
            list_del(&pos->list);
            free(pos);

            ES_PRT_INFO("AHU: del device id[%s] \n", pos->device_id);
        }
    }
}

static void del_dev(struct json_object *jroot)
{
    del_dev_from_dp(jroot);
    del_dev_from_local(jroot);
}

/* 处理topic：local/gateway/+/command
 * @Msg: mqtt raw payload 
 * @Topic: Mqtt topic
 */
void ahu_mqtt_cmd_msg_proc(char *msg, char *topic)
{
    const char *cmd;
    struct json_object *jroot, *jcmd_val;

    /* string -> json */
    jroot = json_tokener_parse(msg);

    /* 提取 cmd 字段，没有cmd 字段的报文不处理  */
    if( !json_object_object_get_ex(jroot, "cmd", &jcmd_val) ){
        ES_PRT_INFO("AHU: Rcv command topic json with no \"cmd\". return. \n");
        return;
    }

    cmd = json_object_get_string(jcmd_val);

    if(strcmp(cmd, "addDevice") == 0){
        if(ahu_mqtt_cmd_adddevice(jroot) == Success){
            add_ahu_dev_2local(jroot);
        }

    }else if(strcmp(cmd, "write") == 0){
        ahu_mqtt_cmd_write(jroot);
        update_points_2local(jroot);
    
    }else if(strcmp(cmd, "delDevice") == 0){
        del_dev(jroot);
    }

    json_object_put(jroot);
//    printf_debug();

}

/* 处理这种 topic：local/gateway/+ */
void ahu_mqtt_msg_proc(char *msg)
{
    struct json_object *jroot, *jdk, *jfunc;

    /* string -> json */
    jroot = json_tokener_parse(msg);

    if( !json_object_object_get_ex(jroot, "deviceKey", &jdk) ){
        return;
    }

    if( !json_object_object_get_ex(jroot, "function", &jfunc) ){
        return;
    }

    /* 遍历function中的每个条目 */
    json_object_object_foreach(jfunc, key, jval){
        update_points_2dev(json_object_get_string(jdk), key, jval);
    }

    json_object_put(jroot);

}